package service

import (
	"hy_808/configor"
	"hy_808/di"
	"hy_808/global"
	"hy_808/logdot"
	"hy_808/protocol/hygprs"
	"hy_808/protocol/jtt808"
	"hy_808/protocol/jtt808/packet/d2p"
	"hy_808/tcpx"
	"hy_808/util"
	"log"
	"time"
)

var HyClient = ClientHyService{
	Logger: di.Logdot(),
}

type ClientHyService struct {
	Logger *logdot.Logdot
}

func (this *ClientHyService) OnReceive(c *tcpx.Conn, p hygprs.Receive) bool {
	switch p.Header {
	case hygprs.FromBus:
		switch p.Type {
		case 0x82 /*车载端登录包*/ :
			p2 := hygprs.MakeFields(p.Packet)
			busId := p2.BusID()
			log.Printf("车载登录,车号%d,线路%d", busId, p2.LineID())
			//山东济南 历下区
			//c := configor.ConfigGlobal.DeviceInfo
			//DeviceEntity.SetDevice(busId, c.ProvinceId, c.CityId, c.ProducerId, "132020031234564132020031234564", c.Model, "018800001267", 5, "鲁A03124")
			////注册到808平台
			//DeviceEntity.Reg808(busId)
			//AnswerRequired(p2)
		case 0x02:
		case 0x83: /*车载端行驶包*/
			p2 := hygprs.MakeFields(p.Packet)
			busId := p2.BusID()
			lineId := p2.LineID()
			log.Printf("行驶包,车号%d,线路%d", busId, lineId)
			//检查是否已经登录
			dc := DeviceEntity.GetDevice(busId)
			if dc == nil {
				//山东济南 历下区
				c := configor.ConfigGlobal.DeviceInfo
				dcData, err := util.GetDeviceDBData(int(busId))
				if err != nil {
					this.Logger.Warn("设备未保存,手动生成资料", err)
					dcData = SetDeviceBasic(int(busId), int(lineId))
					//break
				}
				//dc = DeviceEntity.SetDevice(busId, c.ProvinceId, c.CityId, c.ProducerId, dcData.DeviceId, c.Model, dcData.Phone, dcData.Color, dcData.PlateNo)
				dc = DeviceEntity.SetDevice(busId, c.ProvinceId, c.CityId, c.ProducerId, "132020031234564132020031234564", c.Model, "018800001267", 5, dcData.PlateNo)
				this.RegisterExec(dc)
			}
			//发送心跳
			DeviceEntity.HeartbeatDC(dc)
			//发送位置
			DeviceEntity.LocationDC(dc, 0, p2, 0x00, []byte{})
		case 0x86, 0x06: /*高级别报警*/
			p2 := hygprs.MakeFields(p.Packet)
			bus := p2.BusID()
			dc := DeviceEntity.GetDevice(bus)
			if dc != nil {
				alarmId, attachId, attach := this.HighAlarmHandle(p2)
				if len(attach) > 0 {
					DeviceEntity.LocationDC(dc, alarmId, p2, attachId, attach)
				}
			}
		default:

		}
	}
	return true
}

func (this *ClientHyService) RegisterExec(dc *global.DeviceClient) {
	if dc.TokenCode != "" { //存在鉴权码直接鉴权码登录
		DeviceEntity.Auth808(dc.BusNo)
		return
	}
	//注册到808平台
	DeviceEntity.Reg808(dc.BusNo)
}

var alarmIdNo int //报警ID 从0递增

// 高级别报警处理 返回报警标识 和附加数据
func (this *ClientHyService) HighAlarmHandle(p hygprs.Fields) (uint32, byte, []byte) {
	switch p.Byte(0x35) { //上层报警类型
	case 0x3f: //疲劳报警
		var attach []byte
		//报警ID 2字节 [0:4]
		alarmIdNo++
		alarmId := jtt808.FromUint32(uint32(alarmIdNo))
		//标志状态 1字节 [4:5] 报警类型无需开始和结束 填入0x00即可
		iden := []byte{0x00}
		//报警/事件类型 1字节 [5:6]
		theTypeVal := 0x00
		sp := p.Byte(0x0f)
		switch sp {
		case 0x01, 0x02, 0x06: //一级疲劳,二级疲劳,打哈欠
			theTypeVal = 0x01 //生理疲劳
			break
		case 0x03: //抽烟
			theTypeVal = 0x03 //抽烟报警
			break
		case 0x04: //打电话
			theTypeVal = 0x02 //接打手持电话报警
			break
		case 0x05, 0x07, 0x08, 0x0c: //低头,左顾右盼,聊天,喝水
			theTypeVal = 0x04 //不目视前方报警
			break
		case 0x09: //遮挡
			theTypeVal = 0x13 //设备遮挡失效事件
			break
		case 0x0a: //未系安全带
			theTypeVal = 0x0a //未系安全带
			break
		case 0x0b: //无司机
			theTypeVal = 0x11 //驾驶员变更事件
			break

		}
		theType := []byte{byte(theTypeVal)}
		//报警级别 预留 1字节 [6:7]
		alarmLevel := []byte{0x00}
		//疲劳程度 报警类型0x01时有效 范围1-10 1字节 [7:8]
		fatigueLevel := []byte{p.Byte(0x0f)}
		//预留字段 [8:12]
		reserve := []byte{0x00, 0x00, 0x00, 0x00}
		//车速 1字节 0-250 [12:13]
		speed := []byte{byte(p.Speed())}
		//高程 2字节 [13:15]
		height := jtt808.FromUint16(60)
		//纬度 4字节[15:19]  10的6次方
		lon := jtt808.FromUint32(p.Longitude())

		//经度 4字节[19:23]  10的6次方
		lat := jtt808.FromUint32(p.Latitude())
		//日期时间 bcd[6]
		theTime := jtt808.Number2bcd(time.Now().Local().Format("060102150405"))
		//车辆状态 2字节
		busStatus := []byte{0x00, 0x01}
		//报警标识号
		dc := DeviceEntity.GetDevice(p.BusID())
		alarmIden := append(jtt808.StrToBytes(dc.DeviceId, 7), theTime...)
		alarmIden = append(alarmIden, []byte{0x00, 0x00, 0x00}...)
		//合并附加项数据
		attach = jtt808.SlicesAppend(alarmId, iden, theType, alarmLevel, fatigueLevel, reserve, speed, height, lon, lat, theTime, busStatus, alarmIden)
		return d2p.AlarmFatigue, 0x65, attach //疲劳
	case 0x42: //驾驶辅助报警
		//报警ID 2字节 [0:4]
		alarmIdNo++
		alarmId := jtt808.FromUint32(uint32(alarmIdNo))
		//标志状态 1字节 [4:5] 适用于有开始结束标志的报警或事件类型,报警类型无需开始和结束 填入0x00即可 (目前都为0)
		iden := []byte{0x00}

		//报警/事件类型 1字节 [5:6]
		theTypeVal := 0x00
		detail := p.Byte(0x0f)
		switch detail {
		case 0x01, 0x07, 0x08: //车道偏离,左车道偏离,右车道偏离
			theTypeVal = 0x02 //车道偏离预警
			break
		case 0x02, 0x03, 0x06, 0x0a: //向前碰撞,急加速,前向绝对速度碰撞,低速前向碰撞报警
			theTypeVal = 0x01 //前方车辆碰撞预警
			break
		case 0x04: //急减速
			//theTypeVal = 0x00  //暂无
			break
		case 0x05: //前向相对速度碰撞
			theTypeVal = 0x03 //前向车距过近预警
			break
		case 0x09: //前向行人碰撞
			theTypeVal = 0x04 //行人碰撞预警
			break
		}
		theType := []byte{byte(theTypeVal)}
		//报警级别 预留 1字节 [6:7]
		alarmLevel := []byte{0x00}
		//前车车速 1字节 [7:8]
		frontSpeed := []byte{0x00}
		//前车/行人距离 1字节 [8:9]
		frontGap := []byte{0x00}

		//车道偏离类型 1字节 [9:10]
		var deviationType = []byte{0x00}
		if detail == 0x07 {
			deviationType = []byte{0x01}
		} else if detail == 0x08 {
			deviationType = []byte{0x02}
		}
		//道路标志识别类型 1字节 [10:11]
		roadIden := []byte{0x00}
		//道路标志识别数据 1字节 [11:12]
		roadIdenData := []byte{0x00}
		//车速 1字节 [11:12]
		speed := []byte{byte(p.Speed())}
		//高程 2字节 [13:15]
		height := []byte{0x00, 0x3c}
		//纬度 4字节[15:19]
		lon := jtt808.FromUint32(p.Longitude())
		//经度 4字节[19:23]
		lat := jtt808.FromUint32(p.Latitude())
		//日期时间 bcd[6]
		theTime := jtt808.Number2bcd(time.Now().Local().Format("060102150405"))
		//车辆状态 2字节
		busState := []byte{0x01}
		//报警标识 16字节
		dc := DeviceEntity.GetDevice(p.BusID())
		alarmIden := append(jtt808.StrToBytes(dc.DeviceId, 7), theTime...)
		alarmIden = append(alarmIden, []byte{0x00, 0x00, 0x00}...)

		//合并附加项数据
		attach := jtt808.SlicesAppend(alarmId, iden, theType, alarmLevel, frontSpeed, frontGap, deviationType, roadIden, roadIdenData, speed, height, lon, lat, theTime, busState, alarmIden)

		return d2p.AlarmFatigue, 0x64, attach //辅助驾驶报警 808预警
	}
	return 0, 0x00, []byte{}
}
